package com.dj.mingkong.admin.boot.interceptor;


import com.dj.mingkong.admin.biz.core.config.BaseConfig;
import com.dj.mingkong.common.annotation.RequestLimit;
import com.dj.mingkong.common.constant.RedisConstants;
import com.dj.mingkong.common.exception.ExceptionCode;
import com.dj.mingkong.common.exception.ValidateException;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 接口防刷拦截器
 *
 * @author zenglonghui
 */
@Component
@Slf4j
public class RequestLimitInterceptor implements HandlerInterceptor {
    @Resource
    private RedisTemplate<String, String> redisTemplate;
    @Resource
    private BaseConfig baseConfig;

    @Override
    public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) {
        log.info("接口防刷开始拦截........");
        //方法注解
        final RequestLimit methodAnnotation = ((HandlerMethod) handler).getMethodAnnotation(RequestLimit.class);
        //类注解
        final RequestLimit classAnnotation = ((HandlerMethod) handler).getBean().getClass().getAnnotation(RequestLimit.class);
        if (Objects.nonNull(methodAnnotation)) {
            validateCode(request, methodAnnotation.count(), methodAnnotation.time());
        } else if (Objects.nonNull(classAnnotation)) {
            validateCode(request, classAnnotation.count(), classAnnotation.time());
        } else {
            validateCode(request, baseConfig.getRequestLimitCount(), baseConfig.getRequestLimitTime());
        }
        return true;
    }

    private void validateCode(HttpServletRequest request, int maxSize, long timeOut) {
        final String ip = request.getRemoteAddr();
        final String uri = request.getRequestURI();
        final String key = RedisConstants.REQUEST_LIMIT.concat(uri).concat(ip);
        final Long count = redisTemplate.opsForValue().increment(key, 1);
        if (Objects.isNull(count) || count.equals(1L)) {
            redisTemplate.expire(key, timeOut, TimeUnit.MILLISECONDS);
        }
        if (Objects.nonNull(count) && count > maxSize) {
            log.info("用户IP[{}]访问地址[{}]超过了限定的次数[{}]", ip, uri, maxSize);
            throw new ValidateException(ExceptionCode.REQ_LIMIT.getCode(), ExceptionCode.REQ_LIMIT.getMessage());
        }
    }

    @Override
    public void afterCompletion(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler, Exception ex) {
        log.info("接口防刷调用完成后.........");
    }
}
